package com.changge.module.scheduler.template;

import com.alibaba.ttl.TransmittableThreadLocal;
import com.changge.common.core.enums.CommonErrorCode;
import com.changge.common.core.utils.ExceptionUtil;
import com.changge.common.core.utils.IdUtil;
import com.changge.common.core.utils.StringUtil;
import com.changge.common.core.utils.bean.BeanCopyUtil;
import com.changge.common.mq.service.IRabbitService;
import com.changge.module.scheduler.constant.SchedulerJobConst;
import com.changge.common.models.domain.system.scheduler.SchedulerJobLog;
import com.changge.common.models.dto.system.scheduler.SchedulerJobDTO;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Objects;

/**
 * 定时任务执行模板
 *
 * @author zhangrongkang
 * @since 2024/3/1
 */
@Slf4j
@Component
public abstract class AbstractScheduleJob implements Job {

    @Autowired
    private IdUtil idUtil;

    @Autowired
    @Qualifier("schedulerJobLogProducer")
    private IRabbitService rabbitService;

    /**
     * 本地线程变量
     */
    private static final TransmittableThreadLocal<LocalDateTime> JOB_THREAD_LOCAL = new TransmittableThreadLocal<>();

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 获取定时任务数据传输对象数据
        SchedulerJobDTO schedulerJobDTO = BeanCopyUtil.copy(context.getMergedJobDataMap().get(SchedulerJobConst.TASK_PROPERTIES), SchedulerJobDTO.class);
        try {
            // 执行定时任务前置方法
            before(context);
            // 执行任务
            executeJob(context, schedulerJobDTO);
            // 执行任务后置方法
            after(context, schedulerJobDTO, null);
        } catch (Exception e) {
            log.error("定时任务发生异常: {}", e.getMessage());
            after(context, schedulerJobDTO, e);
        } finally {
            JOB_THREAD_LOCAL.remove();
        }
    }

    /**
     * 定时任务前置方法
     */
    protected void before(JobExecutionContext context) {
        // 记录当前执行时间
        JOB_THREAD_LOCAL.set(LocalDateTime.now());
    }

    /**
     * 定时任务执行方法
     * <p>
     *     由子类重载
     * </p>
     *
     * @param context 工作执行上下文对象
     * @param schedulerJobDTO 定时任务对象
     * @throws Exception 执行过程中的异常
     */
    protected abstract void executeJob(JobExecutionContext context, SchedulerJobDTO schedulerJobDTO) throws Exception;

    /**
     * 定时任务后置方法
     */
    protected void after(JobExecutionContext context, SchedulerJobDTO schedulerJobDTO, Exception e) {
        // 获取定时任务执行时间
        LocalDateTime jobExecuteTime = JOB_THREAD_LOCAL.get();
        // 创建定时任务对象
        SchedulerJobLog schedulerJobLog = new SchedulerJobLog();
        schedulerJobLog.setId(idUtil.nextId());
        schedulerJobLog.setJobId(schedulerJobDTO.getId());
        // 任务执行时间
        schedulerJobLog.setCreateTime(jobExecuteTime);

        schedulerJobLog.setJobName(schedulerJobDTO.getJobName());
        schedulerJobLog.setJobGroup(schedulerJobDTO.getJobGroup());
        schedulerJobLog.setInvokeTarget(schedulerJobDTO.getInvokeTarget());

        // 判断任务是否失败
        if (Objects.nonNull(e)) {
            // 任务状态
            schedulerJobLog.setStatus(Boolean.FALSE);
            // 任务信息
            schedulerJobLog.setJobMessage(StringUtil.substring(ExceptionUtil.getExceptionMessage(e), 0, 2000));
        } else {
            schedulerJobLog.setStatus(Boolean.TRUE);
            schedulerJobLog.setJobMessage(CommonErrorCode.SUCCESS.message());
        }
        // 发送到消息队列中
        rabbitService.sendMessage(schedulerJobLog);
    }

}
